/************************************************************
 * Project Name         [Thinking_In_Java]
 * File Name            [Example_03_Exceptions.java]
 * Creation Date        [24-Jun-2014]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ************************************************************/
package pkg_03_miscellaneous;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.EmptyStackException;
import java.util.Stack;

/**
 * 处理异常的一些注意事项
 * 
 * @author 不落的太阳(Sean Yang)
 * @version 1.0
 * @since JDK 6
 * 
 */
public class Example_03_Exceptions {

	/**
	 * 测试方法(Do not run)
	 * 
	 * @param args
	 *            命令行参数
	 * @throws Throwable
	 */
	public static void main(String[] args) throws Throwable {

		// 尽量避免使用异常, 将异常情况提前检测出来
		Stack<String> stack = new Stack<String>();
		try {
			stack.pop();
		} catch (EmptyStackException e) {
			// ...
		}
		// 应该使用下面的方式以避免使用异常
		if (!stack.isEmpty()) {
			stack.pop();
		}

		// 不要为每个可能会出现异常语句都设置try和catch
		try {
			stack.pop();
		} catch (EmptyStackException e) {
			// ...
		}
		String data = "123";
		try {
			Double.parseDouble(data);
		} catch (NumberFormatException e) {
			// ...
		}
		// 应该使用下面的方式将两个语句放在一个try块中
		try {
			stack.pop();
			Double.parseDouble(data);
		} catch (EmptyStackException e) {
			// ...
		} catch (NumberFormatException e) {
			// ...
		}

		// 避免在方法中throw或者catch错误, 比如内存错误
		@SuppressWarnings("unused")
		String[] array;
		try {
			array = new String[1000];
			// array = new String[10000000];此时会出现OutOfMemoryError异常
		} catch (OutOfMemoryError e) {
			throw e;
		}
		// 直接用下面的代码
		array = new String[1000];

		// 避免总是catch Exception或Throwable, 而要catch具体的异常
		// 这样可以根据不同的异常做不同的处理, 使程序更加清晰
		try {
			stack.pop();
			Double.parseDouble(data);
		} catch (Exception e) {
			// 应该避免catch Exception!!!
		}

		// 不要压制,隐瞒异常.将不能处理的异常向外抛, 而不是catch住之后随便处理
		try {
			Double.parseDouble(data);
		} catch (NumberFormatException e) {
			// ...
			throw e; // 抛出不能处理的异常而不是隐瞒
		}

		// 异常链的用法
		try {
			@SuppressWarnings("unused")
			Connection conn = DriverManager.getConnection("url", "username",
					"password");
		} catch (SQLException e) {
			Throwable th = new Exception("Database error");
			th.initCause(e); // 把原始的异常保存起来
			throw th;
			// 获得原始异常信息
			// Throwable ex = th.getCause();
		}

		// 不要在循环中使用try...catch, 尽量将try...catch放在循环外或避免使用try...catch
		// 在循环中使用try...catch将耗费更多的时间, 尽管没有异常发生
		int i = 0;
		int ntry = 1000000;
		Stack<String> s = new Stack<String>();
		long s1;
		long s2;
		System.out.println("Testing for empty stack");
		s1 = new Date().getTime();
		for (i = 0; i <= ntry; i++) {
			if (!s.empty()) {
				s.pop();
			}
		}
		s2 = new Date().getTime();
		System.out.println((s2 - s1) + " milliseconds");

		System.out.println("Catching EmptyStackException");
		s1 = new Date().getTime();
		for (i = 0; i <= ntry; i++) {
			try {
				s.pop();
			} catch (EmptyStackException e) {
			}
		}
		s2 = new Date().getTime();
		System.out.println((s2 - s1) + " milliseconds");
	}

}
